package com.lwhtarena.netty.netty4.server;

import com.lwhtarena.netty.netty4.util.FileInfo;
import com.lwhtarena.netty.netty4.util.FileInfoBuilder;
import com.lwhtarena.netty.netty4.util.FileTransferProperties;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.util.CharsetUtil;
import io.netty.util.internal.shaded.org.jctools.queues.ConcurrentSequencedCircularArrayQueue;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.ConcurrentMap;

public class SampleFileAdapterHandler extends ChannelInboundHandlerAdapter {
    private static final Logger log = LoggerFactory.getLogger(SampleFileAdapterHandler.class);

    private volatile int byteRead;
    private volatile long start = 0;

    /**
     * 文件默认存储地址
     */
    private String file_dir = FileTransferProperties.getString("file_write_path","/");

    private RandomAccessFile randomAccessFile;
    private File file ;
    private long fileSize = -1 ;

    private static volatile FileInfo fileInfo;

    private static ConcurrentLinkedQueue<byte[]> queue = new ConcurrentLinkedQueue();

    private MappedByteBuffer buffer;


    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {

        if (msg instanceof FileInfo ){
            fileInfo = (FileInfo)msg;
            log.debug("文件信息：{}",fileInfo);
            ctx.close();
            return;
        }

        if (msg instanceof ByteBuf) {
            ByteBuf byteBuf = (ByteBuf) msg;
            int len = byteBuf.readableBytes();
            log.debug("字节长度{}",len);
            byte[] bytes = new byte[len];
            byteBuf.readBytes(bytes);
            byteRead = len;
            String path = "E:\\TEMP\\netty-temp" +File.separator+ UUID.randomUUID()+"."+fileInfo.getFileFormat();

            if(start == 0 && fileInfo!=null){ //只有在文件开始传的时候才进入 这样就减少了对象创建 和可能出现的一些错误
                file = new File(path);
                fileSize = fileInfo.getFilesize();
                randomAccessFile = new RandomAccessFile(file, "rw");
                buffer = randomAccessFile.getChannel().map(FileChannel.MapMode.READ_WRITE, start, fileInfo.getFilesize());
                randomAccessFile.getChannel().close();
            } else {
                queue.add(bytes);
                return;
            }

            if (queue.size() > 0) {
                for (byte[] bytes1:queue){
                    buffer.put(bytes1);
                    start = start + bytes1.length;
                    log.debug("queue 文件接收进度：{},剩余字节：{}",start,fileInfo.getFilesize()-start);
                }

            }
            buffer.put(bytes);

            start = start + byteRead;
            log.debug("文件接收进度：{},剩余字节：{}",start,fileInfo.getFilesize()-start);

            if (byteRead > 0 && (start < fileSize && fileSize != -1)) {
                log.debug("等待剩余数据传输");
            } else {
                buffer.force();
                randomAccessFile.close();
                buffer.clear();
                file = null ;
                fileSize = -1;
                randomAccessFile = null;
                start = 0;
                fileInfo = null;
                //ctx.close();  这步让客户端来做
            }
        }


    }




    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        cause.printStackTrace();

        //当连接断开的时候 关闭未关闭的文件流
        if(randomAccessFile != null ){
            try {
                randomAccessFile.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        ctx.close();
    }

    /**
     * 获取 文件路径
     * @return
     */
    private String getFilePath(){
        if( file != null ) {
            return FileTransferProperties.getString("download_root_path") +"/" + file.getName();
        } else {
            return null ;
        }
    }

}
